#include "World.h"
#include "Utilities.h"

using namespace Hunger;

namespace Hunger
{
	World * World::instance = 0;

	World * World::Instance()
	{
		if(instance == 0)
		{
			instance = new World();
		}
		return instance;
	}

	void World::Begin()
	{
		while(!winterHasCome)
		{
			this->BeginNewDay();
		}
		bool didSurvive = this->DidTribeSurvive();
		if(didSurvive)
		{
			std::cout << "\nThe tribe survived the winter. Game Over." << std::endl;
			std::cin.get();
		}
		else
		{
			std::cout << "\nThe tribe perished this winter. Game Over." << std::endl;
			std::cin.get();
		}
	}

	World::World() 
	: daysUntilWinter(0), daysPassed(0), currentWeather(0), 
	  currentDisaster(0), currentPestilence(0), winterHasCome(false),
	  numDisasters(0), numPestilences(0), disasterYesterday(false), pestilenceYesterday(false)
	{
		mainTribe = new Tribe();
		menagerie = new Menagerie();
	}

	World::~World()
	{
		delete mainTribe;
		mainTribe = 0;

		delete menagerie;
		menagerie = 0;
	}

	void World::BeginNewDay()
	{
		daysPassed++;

		this->DetermineDaysUntilWinter();

		if(daysUntilWinter <= 0)
		{
			winterHasCome = true;
			return;
		}

		this->DetermineWeather();
		this->DetermineDisaster();
		this->DeterminePestilence();

		this->AffectTribes();
		this->AffectMenagerie();

		this->DisplaySelf();
	}

	void World::AffectTribes()
	{
		mainTribe->SetWeather(currentWeather);
		mainTribe->SetDisaster(currentDisaster);
		mainTribe->SetPestilence(currentPestilence);

		mainTribe->UpdateSelf();
	}

	void World::AffectMenagerie()
	{

	}

	void World::DisplaySelf()
	{
		std::cout << "\nHUNGER - Day " << daysPassed << std::endl;
		std::cout << "---------------------------" << std::endl;
		std::cout << "Days Until Winter - " << daysUntilWinter << std::endl;

		std::string weather;
		switch(currentWeather)
		{
			case Weather::Fair:
				weather = "Fair";
				break;
			case Weather::Cloudy:
				weather = "Cloudy";
				break;
			case Weather::Windy:
				weather = "Windy";
				break;
			case Weather::Rainy:
				weather = "Rainy";
				break;
			case Weather::Thunderstorm:
				weather = "Thunderstorm";
				break;
			case Weather::Snow:
				weather = "Snow";
				break;
			case Weather::Blizzard:
				weather = "Blizzard";
				break;
			default:
				break;
		}
		std::cout << "Current Weather - " << weather << "\n";

		std::string disaster;
		switch(currentDisaster)
		{
		case Disaster::No_Disaster:
			disaster = "Luckily, a day without disaster.";
			break;
		case Disaster::Fire:
			disaster = "A wild fire has ignited!";
			break;
		case Disaster::Flood:
			disaster = "There's been a flood!";
			break;
		case Disaster::Tornado:
			disaster = "A devastating tornado has touched down!";
			break;
		case Disaster::Earthquake:
			disaster = "The earth has opened up its gaping jaws!";
			break;
		default:
			break;
		}
		std::cout << "Current Disaster - " << disaster << "\n";

		std::string pestilence;
		switch(currentPestilence)
		{
		case Pestilence::No_Pestilence:
			pestilence = "No pestilence to be found.";
			break;
		case Pestilence::Animal_Plague:
			pestilence = "The animals are sick with plague!";
			break;
		case Pestilence::Human_Plague:
			pestilence = "The people are sick with plague!";
			break;
		default:
			break;
		}
		std::cout << "Current Pestilence - " << pestilence << "\n";

		mainTribe->DisplaySelf();
	}

	void World::DetermineDaysUntilWinter()
	{
		int days = Utilities::Random(28, 31);
		daysUntilWinter = days - daysPassed;
	}

	void World::DetermineWeather()
	{
		int min;
		int max;
		if(daysPassed <= 10)
		{
			min = Weather::Fair;
			max = Weather::Windy;
		}
		else if(daysPassed > 10 && daysPassed < 20)
		{
			min = Weather::Cloudy;
			max = Weather::Rainy;
		}
		else if(daysPassed >= 20 && daysPassed < 25)
		{
			min = Weather::Windy;
			max = Weather::Thunderstorm;
		}
		else if(daysPassed >= 25)
		{
			min = Weather::Rainy;
			max = Weather::Blizzard;
		}
		int weather = Utilities::Random(min, max);
		currentWeather = weather;
	}

	void World::DetermineDisaster()
	{
		if(daysPassed <= 10)
		{
			currentDisaster = Disaster::No_Disaster;
			return;
		}
		else
		{
			int disasterPotential = 0;

			if(mainTribe->GetMorale() <= 5 || mainTribe->GetMorale() >= 95)
			{
				disasterPotential += 15;
			}
			if(mainTribe->GetEmpathy() <= 5 || mainTribe->GetEmpathy() >= 95)
			{
				disasterPotential += 15;
			}
			if(FigureDisasterPercentage() < 15)
			{
				disasterPotential += 25;
			}
			if(FigurePestilencePercentage() < 15)
			{
				disasterPotential += 25;
			}
			if(!disasterYesterday)
			{
				disasterPotential += Utilities::Random(0, 10);
			}

			if(disasterPotential > 60)
			{
				int newDisaster = Utilities::Random(Disaster::Fire, Disaster::Flood);
				currentDisaster = newDisaster;

				numDisasters++;
				disasterYesterday = true;
			}
			else
			{
				currentDisaster = Disaster::No_Disaster;
				disasterYesterday = false;
			}
		}
	}

	void World::DeterminePestilence()
	{
		if(daysPassed <= 10)
		{
			currentPestilence = Pestilence::No_Pestilence;
			return;
		}
		else
		{
			int pestilencePotential = 0;

			if(mainTribe->GetMorale() <= 5 || mainTribe->GetMorale() >= 95)
			{
				pestilencePotential += 15;
			}
			if(mainTribe->GetEmpathy() <= 5 || mainTribe->GetEmpathy() >= 95)
			{
				pestilencePotential += 15;
			}
			if(FigureDisasterPercentage() < 15)
			{
				pestilencePotential += 25;
			}
			if(FigurePestilencePercentage() < 15)
			{
				pestilencePotential += 25;
			}
			if(!pestilenceYesterday)
			{
				pestilencePotential += Utilities::Random(0, 10);
			}

			if(pestilencePotential > 60)
			{
				int newPestilence = Utilities::Random(Pestilence::Human_Plague, Pestilence::Animal_Plague);
				currentPestilence = newPestilence;

				numPestilences++;
				pestilenceYesterday = true;
			}
			else
			{
				currentPestilence = Pestilence::No_Pestilence;
				pestilenceYesterday = false;
			}
		}
	}

	int World::FigureDisasterPercentage()
	{
		float percentage = (numDisasters / daysPassed) * 100;
		return static_cast<int>(percentage);
	}

	int World::FigurePestilencePercentage()
	{
		float percentage = (numPestilences / daysPassed) * 100;
		return static_cast<int>(percentage);
	}

	bool World::DidTribeSurvive()
	{
		if(mainTribe->GetFoodSupply() >= 75)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}